﻿#!/usr/bin/env python
# -*- encoding: utf-8 -*-


# here put the import lib

import wx
import ui_com_setting
import ui_send_setting
import ui_rcv_setting
import ui_para_setting
import ui_log_setting
import ui_about
import ui_help
from configobj import ConfigObj
import threading
from dataConvert import DataConvert
import os
import uart
import struct
import time
import yiwinPanel
import eventManager


# -定义菜单ID,关联Event-------------------------
ID_NEW = 1
ID_OPEN = 2
ID_END = 3
ID_OK = 4
ID_CNACEL = 5
ID_MEASURE = 6

ID_COM = 11
ID_SEND = 12
ID_RCV = 13
ID_PARA = 14
ID_HELP = 15
ID_ABOUT = 16
ID_LOG = 17

mlock = threading.Lock() 

class Yiwin_Frame(wx.Frame):

    def __init__(self,title,parent,size=(900, 750)):
        self.title=title
        self.measurement = ''
        self.dataSaveFile = "data.txt"
        self.readConfig() 

        super(Yiwin_Frame, self).__init__(parent, title= self.title, size = size)

        self.yiwin_panel = yiwinPanel.Yiwin_Panel( self, para = self.ParaSettingData )  # 调用自己建立的 panel 类
        self.list = self.yiwin_panel.list
        self.BoxSizer=wx.BoxSizer(wx.HORIZONTAL)
        self.BoxSizer.Add(self.yiwin_panel, proportion =-10, border = 2,flag = wx.ALL | wx.EXPAND)
    
        self.SetSizer(self.BoxSizer)	
        self.Centre(wx.BOTH)


        self.statusBar = self.CreateStatusBar()  # 创建状态栏
        self.statusBar.SetFieldsCount(2) # 状态栏分成3个区域
        self.statusBar.SetStatusWidths([-1,-1]) #区域宽度比列，用负数
        self.statusBar.SetStatusText( u"上海奕枫仪器设备有限公司 版权所有", 1 ) #给状态栏设文字
        self.statusBar.SetStatusText( u" 等待接收消息......", 0 )

        self.__set_menu()       # 添加菜单
        self.__attach_events()  # 菜单事件
        self.__msgManager()     # 基于事件管理的消息管理
        self.__setTimer()   

        self.__set_properties()
        '''
        # 默认串口配置参数
        # 1;9600;N;8;1  serial number;com parameter
        '''
        self.ComSettingData = {
            "1": "COM1;9600;8;N;1",
            "2": "COM1;9600;8;N;1",
            "3": "COM1;9600;8;N;1"
        }

        '''
        # 默认发送命令格式
        # 是否发送（0，1）,串口号,波特率，数据位，奇偶，停止位,命令，sleeptime(非 timeout)
        # sleep的时间  部分命令需要在特定时间后起作用，没有就默认为0
        '''
        self.SendSettingData = {
            "1": "1;COM1;9600;8;N;1;0103000000044409,0",
            "2": "1;COM1;9600;8;N;1;0103000000044409,0",
            "3": "1;COM1;9600;8;N;1;0103000000044409,0",
            "4": "1;COM1;9600;8;N;1;0103000000044409,0",
            "5": "1;COM1;9600;8;N;1;0103000000044409,0",
            "6": "1;COM1;9600;8;N;1;0103000000044409,0",
            "7": "1;COM1;9600;8;N;1;0103000000044409,0",
            "8": "1;COM1;9600;8;N;1;0103000000044409,0"
        }
        '''
        # 接受配置RCV config
        # 通讯类型，数据转换类型，校验类型，sleeptime(非 timeout)，数据个数；有用字节个数系数，，系数，，
        # 通讯类型        
        #        RTU   :  标注的工业RTU ,CRC校验
        #        ASCII  :  阻塞式ASCII
        #        Hex    :  阻塞型，十六进制无需校验
        #        ASCII2 :  非阻塞式ASCII
        #        Hex2   :  非阻塞型Hex
        #        Other  :  其他
        # 数据转换类型 : 
        #       floatABCD 
        #       floatCDBA 
        #       floatDCBA 
        #       floatBADC 
        #       HEX_ASCII 用于读取序列号等
        #       int2_1
        #       int2_2 
        #       ASCII 
        #       Hex
        # 数据校验类型 
        #       crc16
        #       none
        # 系数
        #       例如得出的结果 乘 *0.01 得到最终结果
        # 数据个数：几条数据,和谁分开
        # 超时时间 或间隔时间
        # 可增加数据输出分隔符类 空格 逗号  分号
        # No. depend on Key
        '''
        self.RcvSettingData = {
            "1": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "2": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "3": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "4": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "5": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "6": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "7": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01",
            "8": "RTU,floatABCD,CRC16,0.2,2,6,22,0.01"
        }

        # 参数配置
        # 名称：单位， 例如： mg/L
        self.ParaSettingData = {
            '1': 'DO1,mg/l',
            '2': 'DO2,mg/l',
            '3': 'DO3,mg/l',
            '4': 'DO4,mg/l',
            '5': 'DO5,mg/l',
            '6': 'DO6,mg/l',
            '7': 'DO,mg/l',
            '8': 'DO,mg/l'
        }
        # Log config
        # 默认时间五分钟
        self.LogSettingData = {
            '1': '5',
            '2': '20'
        }
        
        # # 创建定时器
        # self.timer = wx.Timer(self)#创建定时器
        # self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)#绑定一个定时器事件

    def __set_menu(self):

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        fileMenu.Append(ID_NEW, u'&开始采集')
        fileMenu.Append(ID_OPEN, u'&串口测试')
        fileMenu.Append(ID_MEASURE, u'&单次测量')        
        fileMenu.Append(ID_END, u'&结束采集')
        fileMenu.AppendSeparator()

        menubar.Append(fileMenu, u'&测量  ')

        settingMenu = wx.Menu()
        settingMenu.Append(ID_COM, u'&串口设置', 'Import newsfeed list...')
        settingMenu.Append(ID_SEND, u'&发送参数', 'Import newsfeed list...')
        settingMenu.Append(ID_RCV, u'&接受参数', 'Import newsfeed list...')
        settingMenu.Append(ID_PARA, u'&显示参数', 'Import newsfeed list...')
        settingMenu.Append(ID_LOG, u'&采集', 'Import newsfeed list...')
        menubar.Append(settingMenu, '&设置  ')

        aboutMenu = wx.Menu()
        aboutMenu.Append(ID_HELP, u'&帮助', 'Import newsfeed list...')
        aboutMenu.Append(ID_ABOUT, u'&关于我们', 'Import newsfeed list...')
        menubar.Append(aboutMenu, u'&帮助  ')

        self.SetMenuBar(menubar)

   

    def __set_properties(self):
        # begin __set_properties
        self.SetSize((900, 750))
        self.SetTitle(u'传感器数据采集--上海奕枫仪器设备有限公司')
        self.Centre()


    def __attach_events(self):
        self.Bind(wx.EVT_MENU, self.OnNew, id=ID_NEW)
        self.Bind(wx.EVT_MENU, self.OnMeasure, id=ID_MEASURE)
        self.Bind(wx.EVT_MENU, self.OnOpen, id=ID_OPEN)
        self.Bind(wx.EVT_MENU, self.OnEnd, id=ID_END)
        self.Bind(wx.EVT_MENU, self.OnComSetting, id=ID_COM)
        self.Bind(wx.EVT_MENU, self.OnSendConfig, id=ID_SEND)
        self.Bind(wx.EVT_MENU, self.OnRcvConfig, id=ID_RCV)
        self.Bind(wx.EVT_MENU, self.OnParaConfig, id=ID_PARA)
        self.Bind(wx.EVT_MENU, self.OnHelpConfig, id=ID_HELP)
        self.Bind(wx.EVT_MENU, self.OnAboutConfig, id=ID_ABOUT)
        self.Bind(wx.EVT_MENU, self.OnLogConfig, id=ID_LOG)

    def __msgManager(self):
        EVENT_ARTICAL = "Event_Artical"
        EVENT_MSG = "Event_MSG"
        self.eventManager = eventManager.EventManager()
        self.eventManager.AddEventListener( eventManager.EVENT_MSG, self.doMSG )
        self.eventManager.Start()
        pass

    def __setTimer(self):
        self.timer = wx.Timer(self)   #创建定时器,菜单以后
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) #绑定一个定时器事件
        pass

    # Virtual event handlers, overide them in your derived class
    def OnStart( self, event ):
        self.timer.Start( int( self.LogSettingData['1']) * 60 *1000 )
    
    def OnStop( self, event ):
        self.timer.Stop()
    
    def OnTimer(self, event):
        '''
        采集数据
        '''
        self.logData()

    def doMSG(self, event):
        '''
        * 根据消息类型处理消息
        '''
        #  print( u'Dict：%s'  % event.dict )
        # print(u'正在状态栏显示消息：%s'  % event.dict["StatusMSG"])
        for key,value in event.dict.items():
            if int(key) == 1 :  
                #self.alterStatus_0(value)
                pass
            if int(key) == 2 :
                self.popDialog(value)
            if int(key) == 3 :
                # print("huatu====================")
                # time.sleep(0.01)
                self.OnPlot(event)

    # 消息处理类，定义一个py, 将frame对象， 传递过去
    def alterStatus_0(self,msg):
        self.statusBar.SetStatusText( msg, 0 )

    def popDialog(self,msg):
        with wx.MessageDialog( self, msg, u"错误提示", wx.OK )as dlg:
            dlg.ShowModal()

    def changeList(self,data):
        """
        增加行，删除行
        """
        total = self.list.GetItemCount()
        print ('total %s' %total )
        data = data.split(';')

        if total <= int( self.LogSettingData['2'] ) : 

            indexItem = self.list.InsertItem(total+1, "1")
            i=0
            for  i in range(len(self.ParaSettingData)):            
                self.list.SetItem(indexItem, i, data[i])
        else:
            print( ' i am %s' % self.LogSettingData['2']  )
            indexItem = self.list.InsertItem(total+1, "1")
            i=0
            for  i in range(len(self.ParaSettingData)):            
                self.list.SetItem(indexItem, i, data[i])
            #print (long 2)
            self.list.DeleteItem(total)           

    def readConfig(self):
        # 读取配置文件
        conf_ini = "config.ini"
        config = ConfigObj(conf_ini)
        if 'ComSetting' in config:
            self.ComSettingData = config['ComSetting']
        else:
            pass
        if 'SendSetting' in config:
            self.SendSettingData = config['SendSetting']
        else:
            pass
        if 'RcvSetting' in config:
            self.RcvSettingData = config['RcvSetting']
        else:
            pass
        if 'ParaSetting' in config:
            self.ParaSettingData = config['ParaSetting']
        else:
            pass
        if 'LogSetting' in config:
            self.LogSettingData = config['LogSetting']
        else:
            pass

    def detectComPort(self,Port="COM1",Baudrate="9600",ByteSize="8", Parity="N", Stopbits="1"):
        u = uart.Uart (Port,Baudrate)
        u.connect()
        if u._is_connected == True:
            self.statusBar.SetStatusText(Port + u"&串口可以打开")
            print(Port + ' 串口可以打开')      
        else:
            print(Port + "串口设置有误!!")
            self.statusBar.SetStatusText(Port + u"&串口设置有误")
        
        is_connected = u._is_connected 
        u.disconnect()
        del u
        return  is_connected     

    def logData(self):
        print ( 'logging.....initiate self.meaurement.......' )
        self.measurement = ''        
        for key,value in  self.SendSettingData.items() : 
            mlock.acquire()
            value = list( value.split(';') )
            if value[0] == '1' :
                print(" 第 %s 条命令正在测量 " %key)
                u =uart.Uart(Port = value[1], BaudRate= value[2], ByteSize=value[3],
                    Parity=value[4],Stopbits=value[5],
                    sendCommand=value[6],rcvConfig=self.RcvSettingData[key] )
                u.start_recv_thread (self.processData)
            mlock.release()
            time.sleep(int(value[7]))
        u.disconnect()
        del u
        # 加上时间
        self.measurement = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+';'+self.measurement
        # 保存数据
        print(" 测量完成，数据： %s " % self.measurement)

        #ss= self.measurement.split[';']
        count = len( self.measurement.split(';') )

        print(" 测量完成，数据条数： %s " % count)

        if  count == 0 :
            self.statusBar.SetStatusText(  "  您没有接收到数据!" )
            with wx.MessageDialog(self, u"您接收的数据为空！",u"提示信息", wx.OK )as dlg:
                dlg.ShowModal()
            self.timer.Stop()

        elif (count-2) > len(self.ParaSettingData) :
            with wx.MessageDialog(self, u"您的数据超过了您在参数配置里的设置！",u"提示信息", wx.OK )as dlg:
                dlg.ShowModal()
            self.timer.Stop()
        else :
            #保存数据
            print ( 'saving.....' )
            output = open( self.dataSaveFile , 'a' ,encoding='utf8' )
            output.write(self.measurement+'\n')
            output.close()            
            # 将数据送到ListCtrl
            self.changeList(self.measurement)           

        # 清空measurement
        self.measurement = ''
        # time.sleep(1)

    def processData(self,data):
        '''
        拼接并保存数据
        '''
        print("meaurement %s" %data)
        self.measurement = self.measurement+data

    def __check_port(self):
        self.detectResult = True
        com_port = []
        for value in self.SendSettingData.values():
            if value.split(';')[0] == '1' :
                if value.split(';')[1] in com_port :
                    pass
                else:
                    com_port.append(value.split(';')[1])

        if len(com_port) == 0 :
            self.detectResult = False
        else: 
            for value in com_port:
                if self.detectComPort(Port = value) == False:
                    self.detectResult = self.detectResult and False    

    def __check_data_file_header(self):
        self.sn = u"奕枫仪器数据采集"
        if os.path.exists( self.dataSaveFile ) and os.path.getsize( self.dataSaveFile ) > 0 :
            # 文件存在，且文件不为空
            with open(self.dataSaveFile, 'r') as f_Data :
                first_line  = f_Data.readline()

            first_line  = first_line.strip('\n').split(';')  
            flag = True
            for i in range( len(first_line)):
                if i == 0:
                    flag = flag and True
                elif i > 0 and first_line[i].strip(' ') != self.ParaSettingData[str(i)]:                                     
                    flag = flag and False
                else :
                    pass
            # print(flag)
            # time.sleep(5)
            return flag
			
        else :
            # 文件不存在 写入文件头 paraSetting
            with open( self.dataSaveFile, "w",encoding='utf8') as f :
                    f_line = "/"+self.sn+" "
                    for value in self.ParaSettingData.values():
                        f_line = f_line + "; " +value
                    f.write ( f_line+"\n" )
            return True

    def OnNew(self, e):
        self.readConfig()
        self.__check_port()
        _is_header_ok = self.__check_data_file_header()

        if self.detectResult == False  :
            self.alterStatus_0(  "  您的发送配置中的串口有误,请重新配置")
            self.popDialog( "发送配置中有串口没有检测到，请您仔细检查。" )
        elif  _is_header_ok == False :
            self.alterStatus_0( " 备份并清空数据文件"+ self.dataSaveFile + " ！" )
            self.popDialog( " 备份并清空数据文件"+ self.dataSaveFile + " ！" )
        else :
            #启动定时器工作  开始采集数据
            self.logData()
            self.timer.Start( int( self.LogSettingData['1']) * 60 *1000 )

    def OnMeasure(self,e):
        self.readConfig()
        self.__check_port()
        _is_header_ok = self.__check_data_file_header()

        if self.detectResult == False  :
            self.alterStatus_0(  "  您的发送配置中的串口有误,请重新配置")
            self.popDialog( "发送配置中有串口没有检测到，请您仔细检查。" )
        elif  _is_header_ok == False :
            self.alterStatus_0( " 备份并清空数据文件"+ self.dataSaveFile + " ！" )
            self.popDialog( " 备份并清空数据文件"+ self.dataSaveFile + " ！" )
        else :
            #单次测量
            self.logData()


    def OnOpen(self, e):
        self.readConfig()
        self.detectResult = True
        for value in self.ComSettingData.values():
            value = list( value.split(';') )
            print ( 'value: %s' %value )

            if self.detectComPort(Port = value[0], Baudrate = value[1]) == False:
                print( "串口没检测到")
                self.detectResult = self.detectResult and False
        print (self.detectResult)

        with wx.MessageDialog(self, "串口配置中有串口没有检测到。",u"提示信息", wx.OK )as dlg:
            dlg.ShowModal()

    def OnEnd(self, e):
        self.timer.Stop()

    def OnComSetting(self, e):
        # 调用COM对话框类处理对话框
        self.readConfig()
        with ui_com_setting.UI_Com_Setting(
                self,
                -1,
                "",
                comSetting=self.ComSettingData) as Dialog_Com_Setting:
            Dialog_Com_Setting.CenterOnParent()
            resultCOM = Dialog_Com_Setting.ShowModal()

            if resultCOM == wx.ID_OK:
                print("COM config dialog confirm， call back")
        self.readConfig()        

    def OnSendConfig(self, e):
        # 调用COM对话框类处理对话框
        self.readConfig()
        with ui_send_setting.UI_Send_Setting(
                self,
                -1,
                "",
                sendSetting=self.SendSettingData) as Dialog_Send_Setting:
            Dialog_Send_Setting.CenterOnParent()
            resultSend = Dialog_Send_Setting.ShowModal()

            if resultSend == wx.ID_OK:
                print("Send config dialog confirm， call back")
        self.readConfig()

    def OnRcvConfig(self, e):
        self.readConfig()
        with ui_rcv_setting.UI_Rcv_Setting(
                self,
                -1,
                "",
                rcvSetting=self.RcvSettingData) as Dialog_Rcv_Setting:
            Dialog_Rcv_Setting.CenterOnParent()
            resultRcv = Dialog_Rcv_Setting.ShowModal()

            if resultRcv == wx.ID_OK:
                print("Rcv config dialog confirm， call back")
        self.readConfig()
    def OnParaConfig(self, e):
        self.readConfig()
        with ui_para_setting.UI_Para_Setting(
                self,
                -1,
                "",
                paraSetting=self.ParaSettingData) as Dialog_Para_Setting:
            Dialog_Para_Setting.CenterOnParent()
            resultPara = Dialog_Para_Setting.ShowModal()

            if resultPara == wx.ID_OK:
                print("Para config dialog confirm， call back")
        self.readConfig()

    def OnLogConfig(self, e):
        self.readConfig()
        with ui_log_setting.UI_Log_Setting(
                self,
                -1,
                "",
                logSetting=self.LogSettingData) as Dialog_Log_Setting:
            Dialog_Log_Setting.CenterOnParent()
            resultLog = Dialog_Log_Setting.ShowModal()

            if resultLog == wx.ID_OK:
                print("Log config dialog confirm， call back")
        self.readConfig()

    def OnHelpConfig(self, e):
        with ui_help.UI_Help(
                self,
                -1,
                "") as Dialog_Help:
            resultLog = Dialog_Help.ShowModal()

            if resultLog == wx.ID_OK:
                print("Help info")

    def OnAboutConfig(self, e):
        with ui_about.UI_About(
                self,
                -1,
                "") as Dialog_About:
            resultLog = Dialog_About.ShowModal()

            if resultLog == wx.ID_OK:
                print("Aboutus")

    def OnQuit(self, e):
        self.Close()